using System;
using System.Collections.Generic;
using Habanero.Base;
using Habanero.BO;

namespace FireStarter.Base.BusinessObjectMerger
{

    public class BoPropComparer : EqualityComparer<IBOProp>
    {
        public override bool Equals(IBOProp propX, IBOProp propY)
        {
            if (propX == null && propY == null) return true;
            if (propX == null || propY == null) return false;
            if (propX.Value == null || propY.Value == null)
            {
                if (propY.Value == null && propX.Value != null) return false;
                if (propX.Value == null && propY.Value != null) return false;
            }
            else
            {
                if (propX.Value.GetType() != propY.Value.GetType()) return false;
                if (propX.Value is bool)
                {
                    if ((bool) propX.Value && !(bool) propY.Value) return false;
                    if (!(bool) propX.Value && (bool) propY.Value) return false;
                }
                else
                {
                    if (!Object.Equals(propX.Value, propY.Value)) return false;
                }
            }
            return true;
        }

        public override int GetHashCode(IBOProp obj)
        {
            if (obj == null) return 653653;
            return obj.GetHashCode();
        }
    }

    public class BoComparer : EqualityComparer<IBusinessObject>
    {
        private Predicate<IBOProp> _ignorePropertyDelegate;

        public BoComparer() : this(null) { }
        public BoComparer(Predicate<IBOProp> ignorePropertyDelegate)
        {
            _ignorePropertyDelegate = ignorePropertyDelegate;
        }

        public override bool Equals(IBusinessObject x, IBusinessObject y)
        {
            if (x == null) return y == null;
            if (y == null) return false;
            if (x.GetType() != y.GetType())
            {
                throw new InvalidCastException(
                    string.Format("Cannot cast object of type {0} to the type {1} for comparison.",
                                  x.GetType().Name, y.GetType().Name));
            }
            foreach (IBOProp propX in x.Props)
            {
                if (MustIgnoreProperty(propX)) continue;
                IBOProp propY = y.Props[propX.PropertyName];
                var boPropComparer = new BoPropComparer();
                if (!boPropComparer.Equals(propX, propY)) return false;
            }

            return true;
        }

        private bool MustIgnoreProperty(IBOProp propX)
        {
            if (_ignorePropertyDelegate != null) return _ignorePropertyDelegate(propX);
            return propX.PropertyType == typeof (Guid);
        }

        public override int GetHashCode(IBusinessObject obj)
        {
            throw new System.NotImplementedException();
        }
    }

}